/*
 *
 *  *    Copyright 2020-2021 Luter.me
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *      http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.luter.heimdall.plugins.scheduler.token;

import com.google.common.util.concurrent.ThreadFactoryBuilder;

import com.luter.heimdall.core.config.ConfigManager;
import com.luter.heimdall.core.config.HeimdallProperties;
import com.luter.heimdall.core.token.store.TokenStore;
import org.slf4j.Logger;

import java.time.Duration;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

import static org.slf4j.LoggerFactory.getLogger;

/**
 * Token 缓存 定时清理任务默认实现.
 * <p>
 * 定期清理缓存中的无效 Token
 * <p>
 * 注意:只针对(isSelfExpired)内存缓存有效。
 * <p>
 * 外部缓存，如:redis，具有自动过期机制。
 *
 * @author luter
 */
public class DefaultTokenValidatingScheduler implements TokenValidatingScheduler {
    /**
     * The constant log.
     */
    private static final transient Logger log = getLogger(DefaultTokenValidatingScheduler.class);

    /**
     * 初始化 token 定时清理任务
     *
     * @param tokenStore tokenStore 不为空
     */
    public DefaultTokenValidatingScheduler(TokenStore tokenStore) {
        HeimdallProperties config = ConfigManager.getConfig();
        this.startTask(tokenStore, config.getScheduler().isTokenEnabled(),
                config.getScheduler().getInitialDelay(), config.getScheduler().getTokenPeriod());
    }

    /**
     * 启动清理任务
     *
     * @param tokenStore   tokenStore 不为空
     * @param enabled      是否开启任务
     * @param initialDelay 启动后多少秒，开始执行定时任务。单位：秒
     * @param period       每隔多少秒执行一次。单位：秒
     */
    public void startTask(TokenStore tokenStore, boolean enabled, long initialDelay, long period) {
        if (enabled) {
            log.info("[DefaultTokenValidatingScheduler]:: enabled = [true], initialDelay = [{}], period = [{}]", initialDelay, period);
        } else {
            log.warn("[DefaultTokenValidatingScheduler]:: enabled = [false], initialDelay = [{}], period = [{}]", initialDelay, period);
        }
        if (enabled && null != tokenStore) {
            Runnable runnable = () -> {
                //内存缓存
                if (!tokenStore.isSelfExpired()) {
                    try {
                        log.info("[DefaultTokenValidatingScheduler]::Invoke the token validating schedule  task now.");
                        //执行清理任务
                        tokenStore.clearExpiredTokens();
                    } catch (Exception e) {
                        log.error("[DefaultTokenValidatingScheduler]::error happened while execute token validating task :{}", e.getMessage());
                    }
                }

            };
            //延迟执行时间（秒）最少一分钟
            initialDelay = Math.max(initialDelay, Duration.ofMinutes(1).getSeconds());
            //执行的时间间隔（秒），最少 10 分钟
            period = Math.max(period, Duration.ofMinutes(10).getSeconds());
            log.info("[DefaultTokenValidatingScheduler]::Token validating task is enabled,initialDelay:[{}],period:[{}]", initialDelay, period);
            ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("-thread-%d").setDaemon(true).build();
            ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, namedThreadFactory);
            executorService.scheduleWithFixedDelay(runnable, initialDelay, period, TimeUnit.SECONDS);
        } else {
            log.warn("[DefaultTokenValidatingScheduler]::Token validating task is disabled");
        }

    }

}
